package com.chenxin.wms.process.outbound.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chenxin.common.annotation.WmsLogs;
import com.chenxin.common.core.domain.ProcResult;
import com.chenxin.common.enums.WmsTaskStatus;
import com.chenxin.common.enums.WmsTaskSubType;
import com.chenxin.common.enums.WmsTaskType;
import com.chenxin.common.enums.wms.ObDetailStatus;
import com.chenxin.common.enums.wms.StockStatus;
import com.chenxin.wms.domain.*;
import com.chenxin.wms.domain.dto.OutboundConfirmParams;
import com.chenxin.wms.mapper.*;
import com.chenxin.wms.process.outbound.IProcObMasterStatusUpdate;
import com.chenxin.wms.process.outbound.IProcOutboundConfirmWip;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class ProcOutboundConfirmWip implements IProcOutboundConfirmWip {
    @Autowired
    private ObDetailMapper obDetailMapper;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private WcsTaskMapper wcsTaskMapper;
    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private IProcObMasterStatusUpdate obMasterStatusUpdate;

    @WmsLogs(name = "原料半成品出库确认")
    @Override
    public ProcResult call(OutboundConfirmParams params) {
        if (params == null) {
            return ProcResult.error("outbound_confirm_wip_001", "请求参数不能为空");
        }
        // 获取参数
        Long taskId = params.getTaskId();
        if (taskId == null) {
            return ProcResult.error("outbound_confirm_wip_002", "任务ID不能为空");
        }
        // 如果目标托盘不为空，则需要对其进行校验
        String toContNo = params.getToContNo();
        BigDecimal outQty = params.getOutQty();
        if (outQty == null || outQty.compareTo(BigDecimal.ZERO) < 0) {
            return ProcResult.error("outbound_confirm_wip_003", "出库数量不能小于0");
        }
        Long creator = params.getCreator();
        Date workDate = new Date();
        // 任务信息（按taskId）
        TaskEntity confirmTask = taskMapper.selectById(taskId);
        if (confirmTask == null) {
            return ProcResult.error("outbound_confirm_wip_004", "任务【" + taskId + "】不存在");
        }
        Integer taskStatus = confirmTask.getTaskStatus();
        // 非执行中的任务不能进行出库确认
        if (WmsTaskStatus.PROGRESS.getCode() != taskStatus) {
            return ProcResult.error("outbound_confirm_wip_006", "任务【" + taskId + "】当前状态【" + taskStatus + "】不能出库确认");
        }
        // 任务中常用变量
        String contNo = confirmTask.getFromContNo();
        String taskType = confirmTask.getTaskType();
        String taskSubType = confirmTask.getTaskSubType();
        String spuNo = confirmTask.getSpuNo();
        BigDecimal planQty = confirmTask.getPlanQty();
        String fromPosition = confirmTask.getFromPosition();
        String toPosition = confirmTask.getToPosition();
        String curPosition = confirmTask.getCurPosition();
        String stationNo = confirmTask.getStationNo();
        Long detailId = confirmTask.getDetailId();
        Long stockId = confirmTask.getStockId();

        // 只有出库任务才会做出库确认
        if (!WmsTaskType.SHIPMENT_OUT.getCode().equals(taskType)) {
            return ProcResult.error("outbound_confirm_wip_007", "任务【" + taskId + "】不是出库任务");
        }

        // 判断托盘是否到达目标货位
        if (!toPosition.equals(curPosition)) {
            return ProcResult.error("outbound_confirm_wip_008", "托盘【" + contNo + "】未到达目标货位【" + toPosition + "】");
        }

        // 获取站台的相关信息
        QueryWrapper<StationEntity> stationQW = new QueryWrapper<>();
        stationQW.eq("station_no", stationNo).last("limit 1");
        StationEntity stationInfo = stationMapper.selectOne(stationQW);
        if (stationInfo == null) {
            return ProcResult.error("outbound_confirm_wip_005", "作业站台【" + stationNo + "】未维护基础资料");
        }
        // 获取物料的相关信息
        QueryWrapper<SpuEntity> spuQW = new QueryWrapper<>();
        spuQW.eq("spu_no", spuNo).last("limit 1");
        SpuEntity spuInfo = spuMapper.selectOne(spuQW);
        if (spuInfo == null) {
            return ProcResult.error("outbound_confirm_wip_006", "出库物料【" + spuNo + "】未维护基础资料");
        }
        // 获取单据信息
        ObDetailEntity obDetail = obDetailMapper.selectById(detailId);
        if (obDetail == null) {
            return ProcResult.error("outbound_confirm_wip_009", "任务【" + taskId + "】未匹配到出库单据【" + detailId + "】");
        }
        // 明细计划出库数量
        BigDecimal obPlanQty = obDetail.getObPlanQty();
        // 明细已出数量
        BigDecimal obActualQty = obDetail.getObActualQty();
        // 获取库存信息（根据stockId）
        StockEntity stockInfo = stockMapper.selectById(stockId);
        if (stockInfo == null) {
            return ProcResult.error("outbound_confirm_wip_010", "任务【" + taskId + "】未匹配到库存【" + stockId + "】");
        }
        // 库存总数量
        BigDecimal stockQty = stockInfo.getStockQty();
        // 所有的预分配数量
        BigDecimal lockedQty = stockInfo.getLockedQty();
        // 该库存的余量（如果超发可使用该部分库存）
        BigDecimal remainQty = stockQty.subtract(lockedQty);
        // 最大可出数量
        BigDecimal maxOutQty = remainQty.add(planQty);
        // 出库数量校验（出库数量不能任务的预分配数量+库存剩余数量）
        if (outQty.compareTo(maxOutQty) > 0) {
            return ProcResult.error("outbound_confirm_wip_011", "任务【" + taskId + "】的出库数量【" + outQty + "】大于目标库存可出库数量【" + maxOutQty + "】");
        }
        // 扣减库存
        BigDecimal backQty = stockQty.subtract(outQty);
        stockInfo.setStockQty(backQty);
        if (outQty.compareTo(planQty) > 0 && lockedQty.compareTo(outQty) > 0) {
            stockInfo.setLockedQty(lockedQty.subtract(outQty));
        } else if (outQty.compareTo(planQty) > 0) {
            stockInfo.setLockedQty(BigDecimal.ZERO);
        } else {
            stockInfo.setLockedQty(lockedQty.subtract(planQty));
        }
        // 库存状态
        if (lockedQty.compareTo(outQty) > 0) {
            stockInfo.setStockStatus(StockStatus.ALLOCATED.getCode());
        } else {
            stockInfo.setStockStatus(StockStatus.USABLE.getCode());
        }
        stockInfo.setUpdater(creator);
        stockInfo.setUpdateDate(workDate);
        stockMapper.updateById(stockInfo);
        // 获取任务信息（根据托盘条码）
        QueryWrapper<TaskEntity> taskByContNoQW = new QueryWrapper<>();
        taskByContNoQW.eq("from_cont_no", contNo)
                .eq("task_type", WmsTaskType.SHIPMENT_OUT.getCode())
                .lt("task_status", WmsTaskStatus.COMPLETE.getCode());
        Long taskCountByContNo = taskMapper.selectCount(taskByContNoQW);
        // 获取库存信息（根据托盘条码）
        QueryWrapper<StockEntity> stockByContNoQW = new QueryWrapper<>();
        stockByContNoQW.eq("cont_no", contNo);
        Long stockCountByContNo = stockMapper.selectCount(stockByContNoQW);
        // 以托盘的尾端判断出库确认后托盘的流向（1.空托盘/2.回库/3.继续作业）
        if (stockCountByContNo == 1 && taskCountByContNo == 1 && outQty.compareTo(stockQty) >= 0) {
            // 删除库存（空托盘处理）
            stockMapper.deleteById(stockId);
            // TODO 是否生成空托盘回库搬送任务？
            log.info("托盘【" + contNo + "】已拣空，生成空托盘搬送任务");
        } else if (stockCountByContNo == 1 && taskCountByContNo == 1 && outQty.compareTo(stockQty) < 0) {
            // 托盘直接拣选回库（单任务已拣选完毕回库处理）
            log.info("托盘【" + contNo + "】拣选数量【" + outQty + "】，生成回库任务");
            TaskEntity backTask = new TaskEntity();
            backTask.setTaskType(WmsTaskType.RECEIVE_IN.getCode());
            backTask.setTaskSubType(WmsTaskSubType.PICK_BACK.getCode());
            backTask.setFromContNo(contNo);
            backTask.setSpuNo(spuNo);
            backTask.setPlanQty(backQty);
            backTask.setActualQty(backQty);
            // 哪里拣选从哪里回库
            backTask.setFromPosition(curPosition);
            backTask.setToPosition("入库大货位");
            backTask.setCurPosition(curPosition);
            backTask.setStockId(stockId);
            backTask.setStationNo(stationNo);
            backTask.setWarehouseId(100L);
            backTask.setComments("托盘回库");
            backTask.setCreator(creator);
            backTask.setCreateDate(workDate);
            taskMapper.insert(backTask);
            // 生成设备任务
            log.info("生成搬送回库的设备任务");
        } else if (stockCountByContNo > 1 && taskCountByContNo == 1) {
            // 拣选完成，该托盘还有其他库存一起出库（无业务，需回库）
            List<StockEntity> backStocks = stockMapper.selectList(stockByContNoQW);
            for (StockEntity backStock : backStocks) {
                // 根据库存信息生成回库任务
                TaskEntity taskByStock = new TaskEntity();
                taskByStock.setTaskType(WmsTaskType.RECEIVE_IN.getCode());
                taskByStock.setTaskType(WmsTaskSubType.PICK_BACK.getCode());
                taskByStock.setFromContNo(contNo);
                taskByStock.setSpuNo(backStock.getSpuNo());
                taskByStock.setPlanQty(backStock.getStockQty());
                taskByStock.setActualQty(backStock.getStockQty());
                taskByStock.setFromPosition(curPosition);
                taskByStock.setToPosition("入库大货位");
                taskByStock.setCurPosition(curPosition);
                taskByStock.setStockId(backStock.getStockId());
                taskByStock.setStationNo(stationNo);
                taskByStock.setWarehouseId(100L);
                taskByStock.setComments("托盘回库");
                taskByStock.setCreator(creator);
                taskByStock.setCreateDate(workDate);
                taskMapper.insert(taskByStock);
            }
            // 生成设备任务
            log.info("生成搬送回库的设备任务");
        } else {
            // 拣选完成，该托盘还有其他拣选任务未完成
            log.info("托盘【" + contNo + "】已拣选完毕，生成设备任务");
        }
        // 对当前任务做处理
        confirmTask.setTaskStatus(WmsTaskStatus.COMPLETE.getCode());
        confirmTask.setActualQty(outQty);
        confirmTask.setComments("出库确认完毕");
        confirmTask.setUpdater(creator);
        confirmTask.setUpdateDate(workDate);
        taskMapper.updateById(confirmTask);
        // 处理单据（主单+明细）
        BigDecimal addQty = obActualQty.add(outQty);
        obDetail.setObActualQty(addQty);
        if (obPlanQty.compareTo(addQty) <= 0) {
            obDetail.setObDetailStatus(ObDetailStatus.DONE.getCode());
        }
        obDetail.setUpdater(creator);
        obDetail.setUpdateDate(workDate);
        obDetailMapper.updateById(obDetail);
        // 同步主单状态
        obMasterStatusUpdate.statusUpdateByMasterId(obDetail.getObMasterId(), creator);
        return ProcResult.success("出库确认成功，任务【" + taskId + "】，明细单【" + detailId + "】物料【" + spuNo + "】，出库数量【" + outQty + "】");
    }
}
